#ifndef xpack_test_docker_queue
#define xpack_test_docker_queue
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::test_docker_queue::inc
#include"test/helper.hpp" // 需要放第一
#include"define/nullref.hpp"
#include"docker/queue.hpp"
#include"utils/memory.hpp"
#pragma pop_macro("xuser")

namespace mixc::test_docker_queue{
    xtest("queue") {
        using nlrd = inc::helper::nlrd_counter;

        auto used_bytes = inc::memory::used_bytes();
        {
            inc::queue<nlrd> que;

            // 没有元素时 head/tail 接口无元素
            auto && head = que->head();
            auto && tail = que->tail();
            xassert_eq(head, inc::nullref);
            xassert_eq(tail, inc::nullref);
            xassert_eq(que->length, 0u);
            xassert_eq(que->is_empty, true);

            // 无元素
            uxx times = 0;
            que.foreach([&](uxx i, nlrd & item){
                xassert_eq(item.value, i);
                times++;
            });

            xassert_eq(times, 0u);


            // 添加元素
            for(uxx i = 0; i < 128; i++){
                {
                    que.push(nlrd{i});
                    xassert_nlrd(1/*nrld{i} 构造*/, 0, 1/*que 元素从 nlrd{i} 中移动构造*/, 1/*nlrd{i} 析构*/);
                }

                xassert_nlrd(0, 0, 0, 0);

                {
                    auto && head = que->head();
                    auto && tail = que->tail();
                    xassert_ne(head, inc::nullref);
                    xassert_ne(tail, inc::nullref);
                    xassert_eq(head.value, 0u);
                    xassert_eq(tail.value, i);
                    xassert_eq(que->length, i + 1);
                    xassert_nlrd(0, 0, 0, 0);
                }
                xassert_nlrd(0, 0, 0, 0);

                {
                    auto head = que->head();
                    auto tail = que->tail();
                    xassert_ne(head, inc::nullref);
                    xassert_ne(tail, inc::nullref);
                    xassert_eq(head.value, 0u);
                    xassert_eq(tail.value, i);
                    xassert_eq(que->length, i + 1);
                    xassert_nlrd(0, 2/*head, tail 复制构造*/, 0, 0);
                }
                xassert_nlrd(0, 0, 0, 2/*head，tail 析构*/);

                times = 0;
                que.foreach([&](uxx i, nlrd & item){
                    xassert_eq(item.value, i);
                    times++;
                });

                xassert_eq(times, i + 1);
            }

            xassert_eq(que->is_empty, false);

            for(uxx i = que->length, j = 0; i--; j++){
                {
                    auto head = que->head();
                    xassert_nlrd(0, 1/*head 复制构造*/, 0, 0);
                    auto tail = que->tail();
                    xassert_nlrd(0, 1/*tail 复制构造*/, 0, 0);
                    auto && curr = que.pop();
                    xassert_nlrd(0, 0, 1/* curr 移动构造 */, 1/* 被 pop 的元素析构 */);
                    xassert_ne(head, inc::nullref);
                    xassert_ne(tail, inc::nullref);
                    xassert_eq(curr->is_hold_value, true);
                    xassert_eq(head.value, j);
                    xassert_eq(tail.value, 127u);
                    xassert_eq(curr->value().value, j);
                    xassert_eq(que->length, i);
                    xassert_nlrd(0, 0, 0, 0);
                }
                xassert_nlrd(0, 0, 0, 3/* head, tail, curr 析构 */);

                times = 0;
                que.foreach([&](uxx index, nlrd & item){
                    xassert_eq(item.value, index + j + 1);
                    times++;
                });

                xassert_eq(times, i);
            }

            times = 0;
            que.foreach([&](uxx i, nlrd & item){
                xassert_eq(item.value, i);
                times++;
            });

            xassert_eq(que->is_empty, true);
            xassert_eq(times, 0u);
        }

        // 没有元素时 pop
        {
            inc::queue<nlrd> que;
            auto empty = que.pop();
            xassert_eq(empty->is_hold_value, false);
            xassert_eq(que->length, 0u);
            xassert_nlrd(0, 0, 0, 0);
        }

        // 有一个元素时多次 pop 
        {
            nlrd foo;
            xassert_nlrd(1, 0, 0, 0);

            inc::queue<nlrd> que;
            que.push(nlrd{1024});
            xassert_nlrd(1/* nlrd{1024} 正常构造*/, 0, 1/* que 元素从 nlrd{1024} 中移动构造 */, 1/* nlrd{1024} 析构*/);
            que->tail(nlrd{1023});
            xassert_nlrd(1/* nlrd{1023} 正常构造*/, 0, 0/* 由于 que 最后一个元素已经存在，所以不再构造而是赋值*/, 1/* nlrd{1023} 析构*/);
            xassert_alr(0, 1/* que 元素被 nlrd{1023} 赋值，由于nlrd{1023} 是右值，所以这里是右值赋值*/);
            que->head(nlrd{1024});

            //  同 tail 的赋值操作
            xassert_nlrd(1, 0, 0, 1);
            xassert_alr(0, 1);

            que->head(foo);
            xassert_nlrd(0, 0, 0, 0);
            xassert_alr(1/* que 元素被 foo 赋值，由于 foo 是左值，所以这里是左值赋值*/, 0);

            que.pop();
            xassert_nlrd(0, 0, 1/* que 元素移动构造到 value_holder */, 2/* que 被 pop 的元素和 value_holder 依次析构*/);

            // 没有元素
            auto empty = que.pop();
            xassert_eq(empty->is_hold_value, false);
            xassert_eq(que->is_empty, true);
            xassert_eq(que->length, 0u);
            xassert_nlrd(0, 0, 0, 0);

            // 没有元素
            auto && head = que->head();
            auto && tail = que->tail();
            xassert_nlrd(0, 0, 0, 0);
            xassert_eq(head, inc::nullref);
            xassert_eq(tail, inc::nullref);
            xassert_eq(que->is_empty, true);
        }

        xassert_nlrd(0, 0, 0, 1/* foo */);
        xassert_eq(used_bytes, inc::memory::used_bytes());



        // 多值构造
        used_bytes = inc::memory::used_bytes();
        {
            inc::queue<nlrd> que;
            que.push(0, 1, 2);

            // 由于传的是 nlrd 构造时所需的参数，而不是 nlrd，所以不存在移动构造和析构
            xassert_nlrd(3, 0, 0, 0);
            xassert_alr(0, 0);

            que.foreach([&](uxx index, nlrd & item){
                auto expect = index;
                xassert_eq(expect, item.value);
            });

            que.push(3, 4, 5);

            que.foreach([&](uxx index, nlrd & item){
                auto expect = index;
                xassert_eq(expect, item.value);
            });

            xassert_nlrd(3, 0, 0, 0);
            xassert_alr(0, 0);
        }
        xassert_nlrd(0, 0, 0, 6);
        xassert_eq(used_bytes, inc::memory::used_bytes());
    };
}

#endif
